﻿/*************************************************************************
	> File Name:    dispatch_epoll.h
	> Author:       陈猛
	> Mail:         chenmeng@makeblock.com
	> Created Time: Thu 19 May 2022 01:30:39 AM PDT
	> Description:  
 ************************************************************************/
#ifndef _DISPATCH_EPOLL_H_
#define _DISPATCH_EPOLL_H_

#include "dispatch_process.h"
#if !defined (__MACH__) && !defined (__APPLE__)
#include <sys/epoll.h>
#define _SYS_HAVE_EPOLL_HEADER_FILE_ 1
#else
#include <sys/poll.h>
#endif

namespace dispatch {
class IEvent : public Object
{
public:
    enum Type { None, LocalEvent, InotifyEvent, };
    IEvent(Type t = None) : m_type(t) {}

    Type m_type;
};

#if _SYS_HAVE_EPOLL_HEADER_FILE_
typedef enum {
    EPOLL_EVENT_READABLE     = EPOLLIN,
    EPOLL_EVENT_WRITEABLE    = EPOLLOUT,
    EPOLL_EVENT_URGENT       = EPOLLPRI,
    EPOLL_EVENT_ERROR        = EPOLLERR,
    EPOLL_EVENT_HUP          = EPOLLHUP,
    EPOLL_EVENT_EDGE_TRIGGER = EPOLLET,
    EPOLL_EVENT_ONESHOT      = EPOLLONESHOT,
} EPOLL_EVENT_E;
#else
typedef enum {
    EPOLL_EVENT_READABLE  = POLLIN,
    EPOLL_EVENT_WRITEABLE = POLLOUT,
    EPOLL_EVENT_URGENT    = POLLPRI,
    EPOLL_EVENT_ERROR     = POLLERR,
    EPOLL_EVENT_HUP       = POLLHUP,
} EPOLL_EVENT_E;
#endif // _SYS_HAVE_EPOLL_HEADER_FILE_

template<typename R>
class ICB
{
public:
    ICB() {}
    virtual ~ICB() {}
    virtual R operator()(IEvent& e) = 0;
    virtual bool operator==(ICB<R>& icb) = 0;
};

template<typename T, typename R>
class CB : public ICB<R>
{
public:
    CB(T* t, R  (T::*f)(IEvent&) ):m_t(t),m_f(f) {}
    virtual ~CB() {}
    R operator()(IEvent& e) { if(m_t && m_f) return (m_t->*m_f)(e); return R(); }
    bool operator==(ICB<R>& icb)
    {
        CB<T, R>* cb = dynamic_cast<CB<T, R>* >(&icb);
        return (cb && this->m_t==cb->m_t && this->m_f==cb->m_f);
    }

    T* m_t;
    R  (T::*m_f)(IEvent&);
};

template<typename T>
class CBV : public ICB<void>
{
public:
    CBV(T* t, void  (T::*f)(int sig, void *ptr) )
        : m_t(t), m_f(f)
    {}
    virtual ~CBV() {}
    void operator()(int sig, void *ptr) { if(m_t && m_f) return (m_t->*m_f)(sig, ptr); }

    T* m_t;
    void  (T::*m_f)(int sig, void *ptr);
};

template<typename R>
class CCB : public ICB<R>
{
public:
    CCB(R (*f)(IEvent&) ):m_f(f) {}
    virtual ~CCB() {}
    R operator()(IEvent& e) { if(m_f) return m_f(e); return R(); }
    bool operator==(ICB<R>& icb)
    {
        CCB<R>* cb = dynamic_cast<CCB<R>* >(&icb);
        return (cb && this->m_f==cb->m_f);
    }

    R  (*m_f)(IEvent&);
};

class EPoll;
class IEPoll : public Object
{
public:
    IEPoll()
        : m_icb(nullptr), m_epoll(nullptr)
    {}
    ~IEPoll()
    {
        if (m_icb) delete m_icb;
    }

    virtual void read() {}
    virtual void write() {}
    virtual void readUrgent() {}
    virtual void error();
    virtual void hup();

    template<typename R> void setCallBack(R* t, void (R::*f)(IEvent&)) { m_icb = new CB<R, void>(t, f); }

protected:
    void runCb(IEvent &obj)
    {
        if (m_icb) (*m_icb)(obj);
    }

    ICB<void>* m_icb;
    EPoll    * m_epoll;
};

#ifndef _SYS_HAVE_EPOLL_HEADER_FILE_
class PollPrivate;
#endif
class EPoll
{
protected:
#if _SYS_HAVE_EPOLL_HEADER_FILE_
    int32_t m_epollfd;
    int32_t m_nMaxFdNum;
    struct epoll_event* m_pEvents;
#else
    PollPrivate *d;
#endif
public:
    EPoll(const int32_t& nMaxFdNum = 16);

    virtual ~EPoll();

    bool addFd(const int32_t& fd, const uint32_t& state, IEPoll* pData);

    bool deleteFd(const int32_t& fd, IEPoll* /*ptr*/);

    bool modifyFd(const int32_t& fd, const uint32_t& state, IEPoll* ptr);

    int32_t pollProc(int msec);

    //! 等待，可读，单位：毫秒(ms)
    bool selectSock(int ms, IEPoll*);
    bool selectWRSock(int ms, IEPoll*);
};

class LocalEventSock : public IEPoll
{
public:
    enum {
        MSG_WAKEUP_,
        MSG_INNER_MAX,
    };
    class Event : public IEvent
    {
    public:
        Event()
            : IEvent(LocalEvent), m_sig(0), m_ptr(0)
        {}
        Event(int sig, void *ptr)
            : IEvent(LocalEvent), m_sig(sig), m_ptr(ptr)
        {}

        int   m_sig;
        void *m_ptr;
    };
    LocalEventSock();
    ~LocalEventSock();

    // monitor
    bool addInEPoll(EPoll *ep);
    void postEvent(int sig, void *ptr = nullptr);

    void read() override;
    void error() override;
    void hup() override;

    // notify
    void wakeUp();

    void destory();
private:
    int m_monitor;
    int m_notify;
};
}


#endif // _DISPATCH_EPOLL_H_

